﻿using System;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

using RegexEditor.Properties;
using RegexEditor.RegexLib;

namespace RegexEditor
{
	public partial class SearchRegexLibControl : UserControl
	{
		#region Private Fields

		private MainForm _parentForm;

		#endregion

		#region Constructors

		public SearchRegexLibControl()
		{
			InitializeComponent();
			ratingComboBox.SelectedIndex = ratingComboBox.Items.Count - 1;
		}

		#endregion

		#region Public Members

		public new MainForm ParentForm
		{
			get
			{
				if (_parentForm == null)
					_parentForm = FindForm() as MainForm;

				return _parentForm;
			}
		}

		public Panel ResultsPanel { get; set; }

		[Browsable(false)]
		public DataSet SearchResults { get; protected set; }

		public void DisplayAllSearchResults()
		{
			using (new PaintLock(ResultsPanel))
			{
				ResultsPanel.SuspendLayout();
				ResultsPanel.Controls.Clear();

				if (SearchResults.Tables[0].Rows.Count > 0)
				{
					foreach (DataRow row in SearchResults.Tables[0].Rows.Cast<DataRow>().Take(100))
					{
						string title = FixPatternTitle(row.Field<string>("Title"));

						LinkLabel titleLink = new LinkLabel
						{
							Text = string.Format("{0}, by {1}", title, Decode(row.Field<string>("AuthorName"))),
							AutoSize = true,
							LinkArea = new LinkArea(0, title.Length),
							Font = new Font(Font, FontStyle.Bold),
							Margin = new Padding(0, 0, 0, 0),
							Tag = row
						};

						titleLink.LinkClicked += (sender, e) => { DisplaySearchResultItem(((Control)sender).Tag as DataRow); };
						ResultsPanel.Controls.Add(titleLink);

						int rating = row.Field<int>("Rating");
						if (rating > 0)
							ResultsPanel.Controls.Add(new Label
							{
								Text = string.Format("Rating: {0}/5", rating),
								AutoSize = true,
								ForeColor = SystemColors.GrayText,
								Margin = new Padding(4, 0, 0, 4)
							});

						ResultsPanel.Controls.Add(new Label
						{
							Text = Decode(row.Field<string>("Description").Truncate(500)),
							AutoSize = true,
							Margin = new Padding(4, 0, 0, 12)
						});
					}
				}
				else
					ResultsPanel.Controls.Add(new Label
					{
						Text = "RegexLib.com search engine returned no result.",
						AutoSize = true,
						Font = new Font(Font, FontStyle.Bold)
					});

				ResultsPanel.AutoScrollPosition = new Point(0, 0);
				ResultsPanel.ResumeLayout();
			}
		}

		public void DisplaySearchResultItem(DataRow row)
		{
			using (new PaintLock(ResultsPanel))
			{
				ResultsPanel.Controls.Clear();

				ResultsPanel.Controls.Add(new Label
				{
					Text = string.Format("{0}, by {1}", FixPatternTitle(row.Field<string>("Title")), Decode(row.Field<string>("AuthorName"))),
					AutoSize = true,
					Font = new Font(Font, FontStyle.Bold),
					Margin = new Padding(0, 0, 0, 4)
				});

				int rating = Convert.ToInt32(row["Rating"]);
				if (rating > 0)
					ResultsPanel.Controls.Add(new Label
					{
						Text = string.Format("Rating: {0}/5", rating),
						AutoSize = true,
						ForeColor = SystemColors.GrayText,
						Margin = new Padding(4, 0, 0, 4)
					});

				ResultsPanel.Controls.Add(new Label
				{
					Text = Decode(row.Field<string>("Description")),
					AutoSize = true,
					Margin = new Padding(4, 0, 0, 8)
				});

				ResultsPanel.Controls.Add(new Label
				{
					Text = "Matches:",
					AutoSize = true,
					Font = new Font(Font, FontStyle.Bold),
					Margin = new Padding(4, 0, 0, 2)
				});

				ResultsPanel.Controls.Add(new Label
				{
					Text = Decode(row.Field<string>("MatchingText")).Replace("|||", Environment.NewLine),
					AutoSize = true,
					ForeColor = Color.Green,
					Margin = new Padding(8, 0, 0, 4)
				});

				ResultsPanel.Controls.Add(new Label
				{
					Text = "Does not match:",
					AutoSize = true,
					Font = new Font(Font, FontStyle.Bold),
					Margin = new Padding(4, 0, 0, 2)
				});

				ResultsPanel.Controls.Add(new Label
				{
					Text = Decode(row.Field<string>("NonMatchingText")).Replace("|||", Environment.NewLine),
					AutoSize = true,
					ForeColor = Color.FromArgb(0xCC, 0x00, 0x00),
					Margin = new Padding(8, 0, 0, 8)
				});

				ResultsPanel.Controls.Add(new Label
				{
					Text = "Pattern:",
					AutoSize = true,
					Font = new Font(Font, FontStyle.Bold),
					Margin = new Padding(4, 0, 0, 2)
				});

				ResultsPanel.Controls.Add(new Label
				{
					Text = Decode(row.Field<string>("Pattern")),
					AutoSize = true,
					Font = Settings.Default.SideTools_Font,
					Margin = new Padding(8, 0, 0, 8)
				});

				Button useButton = new Button
				{
					Text = "Use this pattern",
					Width = 100,
					Margin = new Padding(4, 0, 0, 8)
				};

				useButton.Click += (sender, e) => { UsePattern(row); };
				ResultsPanel.Controls.Add(useButton);

				LinkLabel goBack = new LinkLabel
				{
					Text = "Back to search results",
					AutoSize = true,
					Font = new Font(Font, FontStyle.Bold),
					Margin = new Padding(0, 0, 0, 8)
				};

				goBack.LinkClicked += (sender, e) => { DisplayAllSearchResults(); };
				ResultsPanel.Controls.Add(goBack);

				LinkLabel moreDetails = new LinkLabel
				{
					Text = "More details at RegexLib.com",
					AutoSize = true,
					Margin = new Padding(0, 0, 0, 12),
					Tag = row["ExpressionId"]
				};

				moreDetails.LinkClicked += (sender, e) => {
					Process.Start(string.Format("http://regxlib.com/REDetails.aspx?regexp_id={0}", ((Control)sender).Tag));
				};

				ResultsPanel.Controls.Add(moreDetails);
				ResultsPanel.AutoScrollPosition = new Point(0, 0);
			}
		}

		public void UsePattern(DataRow row)
		{
			StringBuilder sampleText = new StringBuilder();
			sampleText.AppendLine(row.Field<string>("MatchingText").Replace("|||", Environment.NewLine));
			sampleText.Append(row.Field<string>("NonMatchingText").Replace("|||", Environment.NewLine));

			ParentForm.LoadExpression(new SavedExpression
			{
				Pattern = Decode(row.Field<string>("Pattern")),
				TextToMatch = Decode(sampleText.ToString()),
				Options = System.Text.RegularExpressions.RegexOptions.None,
				OneStringPerLine = true,
				Title = string.Format("{0}, by {1} (from RegexLib.com)", FixPatternTitle(row.Field<string>("Title")), Decode(row.Field<string>("AuthorName")))
			});
		}

		#endregion

		#region Private Members

		private static string Decode(string value)
		{
			value = value.Replace("&amp;", "&");
			value = value.Replace("&lt;", "<");
			value = value.Replace("&gt;", ">");
			value = value.Replace("&quot;", "\"");
			return value;
		}

		private static string FixPatternTitle(string title)
		{
			if (title == "Pattern Title")
				return "Untitled Pattern";

			return Decode(title);
		}

		private int GetMinimumRating()
		{
			switch (ratingComboBox.SelectedIndex)
			{
				case 0:
					return 5;
				case 1:
					return 4;
				case 2:
					return 3;
				default:
					return 0;
			}
		}

		private void searchButton_Click(object sender, EventArgs e)
		{
			progressBar.Visible = true;
			searchButton.Enabled = false;

			SearchParameters parameters = new SearchParameters
			{
				Keywords = keywordCheckBox.Checked ? searchTextBox.Text : null,
				Pattern = patternCheckBox.Checked ? searchTextBox.Text : null,
				MinimumRating = GetMinimumRating()
			};

			if (!backgroundWorker.IsBusy)
				backgroundWorker.RunWorkerAsync(parameters);
		}

		private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
		{
			SearchParameters parameters = (SearchParameters)e.Argument;

			using (WebservicesSoapClient client = new WebservicesSoapClient())
				e.Result = client.listRegExp(parameters.Keywords, parameters.Pattern, parameters.MinimumRating, 10);
		}

		private void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
		{
			SearchResults = e.Result as DataSet;

			if (ResultsPanel != null)
				DisplayAllSearchResults();

			searchButton.Enabled = true;
			progressBar.Visible = false;
		}

		private void searchTextBox_KeyDown(object sender, KeyEventArgs e)
		{
			if (e.KeyCode == Keys.Enter)
			{
				searchButton_Click(searchButton, EventArgs.Empty);
				e.SuppressKeyPress = true;
			}
		}

		private void searchTextBox_TextChanged(object sender, EventArgs e)
		{
			searchButton.Enabled = !string.IsNullOrWhiteSpace(searchTextBox.Text);
		}

		#endregion

		#region Nested Types

		private class SearchParameters
		{
			public string Keywords { get; set; }
			public string Pattern { get; set; }
			public int MinimumRating { get; set; }
		}

		#endregion
	}
}
